<?php

class Concentre_Application_Resource_Daemon extends Zend_Application_Resource_ResourceAbstract
{
    protected $_isChildren = false;
    protected $_ppid;
    protected $_pid;
    
    public function init()
    {
	return $this;
    }
   
    public function start() {
	if ($this->_options['disabled']) {
			return $this;
	}
		
   		if (substr(PHP_OS, 0, 3) === 'WIN') {
            require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('Cannot run on windows');
        } else if (!in_array(substr(PHP_SAPI, 0, 3), array('cli', 'cgi'))) {
            require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('Can only run on CLI or CGI enviroment');
        } else if (!function_exists('shmop_open')) {
            require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('shmop_* functions are required');
        } else if (!function_exists('pcntl_fork')) {
            require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('pcntl_* functions are required');
        } else if (!function_exists('posix_kill')) {
            require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('posix_* functions are required');
        }

  		$oldpid = @file_get_contents($this->_options['pidfile']);

      	if ($oldpid !== false && posix_kill(trim($oldpid),0)) {	
            require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('Daemon already running.');
		}

        ob_end_flush();
      	$pid = pcntl_fork();
		
		if ($pid == -1) {
            require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('Could not fork process.');
		} elseif ($pid) { // we are the parent
			exit(0);
		} 
		
 		$this->_isChildren = true;	
		$this->_pid = posix_getpid();
		$this->_ppid = $ppid;

		@file_put_contents( $this->_options['pidfile'], $this->_pid);
			
 		// set identity
        if (!posix_setgid( $this->_options['gid']) ||
        	!posix_setuid( $this->_options['uid']) ) {
            require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('Could not set identity.');
        }

        // detach from terminal
        if ( -1 == posix_setsid() ) {
        	require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('Could not detach from terminal.');
        }
	
	    // change working directory to prevent from being locked
        if (!@chdir( $this->_options['home'] ) ) {
        	require_once 'Zend/Application/Resource/Exception.php';
            throw new Zend_Application_Resource_Exception('Could not change the working directory.');
        }

      	register_shutdown_function(array(&$this, 'release')); 

		ini_set("max_execution_time", "0");
		ini_set("max_input_time", "0");
		set_time_limit(0);
   		
   		declare(ticks = 1);
      
      	pcntl_signal( SIGTERM, array($this, '_sigHandler') );
        pcntl_signal( SIGINT , array($this, '_sigHandler') );
				
        // change file-mode mask
        umask(0);

	return $this;
    }
	public function stop() {
	
	    if (file_exists($this->_options['pidfile'])) {
	 	$pid = @file_get_contents($this->_options['pidfile']);
                posix_kill($pid, SIGTERM);
	    }

	}

   	public function release() {
   	   if ($this->_isChildren && file_exists($this->_options['pidfile'])) {
       			unlink($this->_options['pidfile']);   		
	   }
	   
   	}

    /**
     *
     * @return void
     */
	 public function _sigHandler($signo) {
	 
		switch ($signo) {
			case SIGINT:
			case SIGTERM:
				exit();
				break;
			case SIGHUP:
			     while (pcntl_waitpid(-1, $status, WNOHANG) > 0);
 				break;
			default:
		}
	}  
}
